﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Input.Touch;

using System.Windows.Threading;

namespace PopTheBalloon2
{
    public class XNAFrameworkDispatcherService : IApplicationService
    {
        private DispatcherTimer frameworkDispatcherTimer;

        public XNAFrameworkDispatcherService()
        {
            this.frameworkDispatcherTimer = new DispatcherTimer();
            this.frameworkDispatcherTimer.Interval = TimeSpan.FromTicks(333333);
            this.frameworkDispatcherTimer.Tick += frameworkDispatcherTimer_Tick;
            FrameworkDispatcher.Update();
        }

        void frameworkDispatcherTimer_Tick(object sender, EventArgs e) { FrameworkDispatcher.Update(); }
        void IApplicationService.StartService(ApplicationServiceContext context) { this.frameworkDispatcherTimer.Start(); }
        void IApplicationService.StopService() { this.frameworkDispatcherTimer.Stop(); }
    }

    public partial class GamePage : PhoneApplicationPage
    {
        ContentManager contentManager;
        GameTimer timer;
        SpriteBatch spriteBatch;

        UIElementRenderer elementRenderer;

        static TimeSpan highScore;

        Texture2D balloon;

        SpriteFont debug;

        TimeSpan inflateTime;

        TimeSpan countdownProceedTime = new TimeSpan(0, 0, 1);
        TimeSpan nextCountdownTime;

        SoundEffect pop;

        bool highScoreSet = false;

        string[] countdown;
        int currentCountdown = 0;

        float scale = 0.1f;
        float maxScale = 1.3f;

        float mod = 0.5f;
        bool gameOver;

        void Reset()
        {
            gameOver = false;
            scale = 0.1f;
            currentCountdown = 0;
            inflateTime = TimeSpan.Zero;
            nextCountdownTime = countdownProceedTime;
        }

        public GamePage()
        {
            InitializeComponent();

            // Get the content manager from the application
            contentManager = (Application.Current as App).Content;

            // Create a timer for this page
            timer = new GameTimer();
            timer.UpdateInterval = TimeSpan.FromTicks(333333);
            timer.Update += OnUpdate;
            timer.Draw += OnDraw;

            countdown = new string[3];
            countdown[0] = "Ready?";
            countdown[1] = "Set...";
            countdown[2] = "Blow!";

            LayoutUpdated += new EventHandler(XNARendering_LayoutUpdated);
        }

        void XNARendering_LayoutUpdated(object sender, EventArgs e)
        {
            // make sure page size is valid
            if (ActualWidth == 0 || ActualHeight == 0)
                return;

            // see if we already have the right sized renderer
            if (elementRenderer != null &&
                elementRenderer.Texture != null &&
                elementRenderer.Texture.Width == (int)ActualWidth &&
                elementRenderer.Texture.Height == (int)ActualHeight)
            {
                return;
            }

            // dispose the current renderer
            if (elementRenderer != null)
                elementRenderer.Dispose();

            // create the renderer
            elementRenderer = new UIElementRenderer(this, (int)ActualWidth, (int)ActualHeight);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // Set the sharing mode of the graphics device to turn on XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

            balloon = contentManager.Load<Texture2D>("balloon");
            debug = contentManager.Load<SpriteFont>("debug");
            pop = contentManager.Load<SoundEffect>("BalloonPop");

            ThunderFish.TMicrophone.Initialize();
            ThunderFish.TMicrophone.StartMonitoring();

            nextCountdownTime = countdownProceedTime;
            currentCountdown = 0;

            inflateTime = TimeSpan.Zero;

            // Start the timer
            timer.Start();

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // Stop the timer
            timer.Stop();

            // Set the sharing mode of the graphics device to turn off XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

            ThunderFish.TMicrophone.Deinitialize();

            base.OnNavigatedFrom(e);
        }

        /// <summary>
        /// Allows the page to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            if (gameOver)
            {
                foreach (TouchLocation t in TouchPanel.GetState())
                {
                    if (t.State == TouchLocationState.Pressed)
                    {
                        Reset();
                    }
                }
            }

            if (currentCountdown >= countdown.Length && !gameOver)
                scale += Math.Max(0, ThunderFish.TMicrophone.Intensity - 0.66f) / mod;

            if (scale >= maxScale)
            {
                if (!gameOver)
                {
                    if (inflateTime < highScore || !highScoreSet)
                    {
                        highScoreSet = true;
                        highScore = inflateTime;
                    }
                    pop.Play();
                }
                gameOver = true;
            }

            if (!gameOver)
                inflateTime += e.ElapsedTime;

            if (currentCountdown < countdown.Length)
            {
                nextCountdownTime -= e.ElapsedTime;
                if (nextCountdownTime <= TimeSpan.Zero)
                {
                    currentCountdown++;
                    nextCountdownTime = countdownProceedTime;
                }
            }
        }

        /// <summary>
        /// Allows the page to draw itself.
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.DeepSkyBlue);

            spriteBatch.Begin();
            if (!gameOver)
                spriteBatch.Draw(
                    balloon,
                    new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Width,
                        SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Height) / 2,
                    null,
                    Color.White,
                    0.0f,
                    new Vector2(balloon.Width, balloon.Height) / 2,
                    scale,
                    SpriteEffects.None,
                    0.0f);
            else
            {
                spriteBatch.DrawString(
                    debug,
                    "Your Time: ",
                    new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Width,
                        SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Height) / 2
                        - debug.MeasureString("Your Time: ") / 2,
                    Color.White);
                spriteBatch.DrawString(
                    debug,
                    inflateTime.ToString(),
                    new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Width,
                        SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Height) / 2
                        - debug.MeasureString(inflateTime.ToString()) / 2
                        + new Vector2(0, debug.MeasureString(inflateTime.ToString()).Y),
                    Color.White);
                spriteBatch.DrawString(
                    debug,
                    "Tap to retry",
                    new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Width,
                        SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Height) / 2
                        - debug.MeasureString("Tap to retry") / 2
                        + new Vector2(0, 100),
                    Color.White);
            }
            if (currentCountdown < countdown.Length)
            {
                spriteBatch.DrawString(
                    debug,
                    countdown[currentCountdown],
                    new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Width,
                        SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Height) / 2
                        - debug.MeasureString(countdown[currentCountdown]) / 2,
                    Color.White);
            }
            else if (scale == 0.1f)
            {
                spriteBatch.DrawString(
                    debug,
                    "Blow into the mic!",
                    new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Width,
                        SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Height) / 2
                        - debug.MeasureString("Blow into the mic!") / 2
                        - new Vector2(0, 80),
                    Color.White);
            }
            if (highScoreSet)
                spriteBatch.DrawString(
                    debug,
                    "Best Time: " + highScore.ToString(),
                    new Vector2(10),
                    Color.White);
            else
                spriteBatch.DrawString(
                    debug,
                    "Best Time: none",
                    new Vector2(10),
                    Color.White);
            /*spriteBatch.DrawString(
                debug,
                ThunderFish.TMicrophone.Intensity.ToString(),
                new Vector2(10),
                Color.White);*/
            elementRenderer.Render();
            spriteBatch.Draw(elementRenderer.Texture, Vector2.Zero, Color.White);
            spriteBatch.End();
        }
    }
}